package org.xbill.DNS;

import java.io.IOException;
import java.io.InterruptedIOException;
import java.io.PrintStream;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

public final class Lookup
{
  public static final int HOST_NOT_FOUND = 3;
  public static final int SUCCESSFUL = 0;
  public static final int TRY_AGAIN = 2;
  public static final int TYPE_NOT_FOUND = 4;
  public static final int UNRECOVERABLE = 1;
  private static Map defaultCaches;
  private static Resolver defaultResolver;
  private static Name[] defaultSearchPath;
  private static final Name[] noAliases = new Name[0];
  private List aliases;
  private Record[] answers;
  private boolean badresponse;
  private String badresponse_error;
  private Cache cache;
  private int credibility;
  private int dclass;
  private boolean done;
  private boolean doneCurrent;
  private String error;
  private boolean foundAlias;
  private int iterations;
  private Name name;
  private boolean nametoolong;
  private boolean networkerror;
  private boolean nxdomain;
  private boolean referral;
  private Resolver resolver;
  private int result;
  private Name[] searchPath;
  private boolean temporary_cache;
  private boolean timedout;
  private int type;
  private boolean verbose;

  static
  {
    refreshDefault();
  }

  public Lookup(String paramString)
    throws TextParseException
  {
    this(Name.fromString(paramString), 1, 1);
  }

  public Lookup(String paramString, int paramInt)
    throws TextParseException
  {
    this(Name.fromString(paramString), paramInt, 1);
  }

  public Lookup(String paramString, int paramInt1, int paramInt2)
    throws TextParseException
  {
    this(Name.fromString(paramString), paramInt1, paramInt2);
  }

  public Lookup(Name paramName)
  {
    this(paramName, 1, 1);
  }

  public Lookup(Name paramName, int paramInt)
  {
    this(paramName, paramInt, 1);
  }

  public Lookup(Name paramName, int paramInt1, int paramInt2)
  {
    Type.check(paramInt1);
    DClass.check(paramInt2);
    if ((!(Type.isRR(paramInt1))) && (paramInt1 != 255))
      throw new IllegalArgumentException("Cannot query for meta-types other than ANY");
    this.name = paramName;
    this.type = paramInt1;
    this.dclass = paramInt2;
    monitorenter;
    try
    {
      this.resolver = getDefaultResolver();
      this.searchPath = getDefaultSearchPath();
      this.cache = getDefaultCache(paramInt2);
      monitorexit;
      this.credibility = 3;
      this.verbose = Options.check("verbose");
      return;
    }
    finally
    {
      monitorexit;
    }
  }

  private void checkDone()
  {
    if ((this.done) && (this.result != -1))
      return;
    StringBuffer localStringBuffer = new StringBuffer("Lookup of " + this.name + " ");
    if (this.dclass != 1)
      localStringBuffer.append(DClass.string(this.dclass) + " ");
    localStringBuffer.append(Type.string(this.type) + " isn't done");
    throw new IllegalStateException(localStringBuffer.toString());
  }

  private void follow(Name paramName1, Name paramName2)
  {
    this.foundAlias = true;
    this.badresponse = false;
    this.networkerror = false;
    this.timedout = false;
    this.nxdomain = false;
    this.referral = false;
    this.iterations = (1 + this.iterations);
    if ((this.iterations >= 6) || (paramName1.equals(paramName2)))
    {
      this.result = 1;
      this.error = "CNAME loop";
      this.done = true;
    }
    while (true)
    {
      return;
      if (this.aliases == null)
        this.aliases = new ArrayList();
      this.aliases.add(paramName2);
      lookup(paramName1);
    }
  }

  /**
   * @deprecated
   */
  public static Cache getDefaultCache(int paramInt)
  {
    monitorenter;
    try
    {
      DClass.check(paramInt);
      Cache localCache = (Cache)defaultCaches.get(Mnemonic.toInteger(paramInt));
      if (localCache == null)
      {
        localCache = new Cache(paramInt);
        defaultCaches.put(Mnemonic.toInteger(paramInt), localCache);
      }
      monitorexit;
      return localCache;
    }
    finally
    {
      localObject = finally;
      monitorexit;
      throw localObject;
    }
  }

  /**
   * @deprecated
   */
  public static Resolver getDefaultResolver()
  {
    monitorenter;
    try
    {
      Resolver localResolver = defaultResolver;
      monitorexit;
      return localResolver;
    }
    finally
    {
      localObject = finally;
      monitorexit;
      throw localObject;
    }
  }

  /**
   * @deprecated
   */
  public static Name[] getDefaultSearchPath()
  {
    monitorenter;
    try
    {
      Name[] arrayOfName = defaultSearchPath;
      monitorexit;
      return arrayOfName;
    }
    finally
    {
      localObject = finally;
      monitorexit;
      throw localObject;
    }
  }

  private void lookup(Name paramName)
  {
    Message localMessage2;
    SetResponse localSetResponse1 = this.cache.lookupRecords(paramName, this.type, this.credibility);
    if (this.verbose)
    {
      System.err.println("lookup " + paramName + " " + Type.string(this.type));
      System.err.println(localSetResponse1);
    }
    processResponse(paramName, localSetResponse1);
    if ((this.done) || (this.doneCurrent))
      return;
    Message localMessage1 = Message.newQuery(Record.newRecord(paramName, this.type, this.dclass));
    try
    {
      localMessage2 = this.resolver.send(localMessage1);
      int i = localMessage2.getHeader().getRcode();
      if ((i != 0) && (i != 3))
      {
        this.badresponse = true;
        this.badresponse_error = Rcode.string(i);
      }
    }
    catch (IOException localIOException)
    {
      while (true)
      {
        while (true)
        {
          while (localIOException instanceof InterruptedIOException)
            this.timedout = true;
          this.networkerror = true;
        }
        if (localMessage1.getQuestion().equals(localMessage2.getQuestion()))
          break;
        this.badresponse = true;
        this.badresponse_error = "response does not match query";
      }
      SetResponse localSetResponse2 = this.cache.addMessage(localMessage2);
      if (localSetResponse2 == null)
        localSetResponse2 = this.cache.lookupRecords(paramName, this.type, this.credibility);
      if (this.verbose)
      {
        System.err.println("queried " + paramName + " " + Type.string(this.type));
        System.err.println(localSetResponse2);
      }
      processResponse(paramName, localSetResponse2);
    }
  }

  private void processResponse(Name paramName, SetResponse paramSetResponse)
  {
    label149: DNAMERecord localDNAMERecord;
    RRset[] arrayOfRRset;
    ArrayList localArrayList;
    int i;
    if (paramSetResponse.isSuccessful())
    {
      arrayOfRRset = paramSetResponse.answers();
      localArrayList = new ArrayList();
      i = 0;
      if (i >= arrayOfRRset.length)
      {
        this.result = 0;
        this.answers = ((Record[])localArrayList.toArray(new Record[localArrayList.size()]));
        this.done = true;
      }
    }
    while (true)
    {
      while (true)
      {
        while (true)
        {
          do
          {
            return;
            Iterator localIterator = arrayOfRRset[i].rrs();
            while (true)
            {
              while (!(localIterator.hasNext()))
                ++i;
              localArrayList.add(localIterator.next());
            }
            if (!(paramSetResponse.isNXDOMAIN()))
              break label149;
            this.nxdomain = true;
            this.doneCurrent = true;
          }
          while (this.iterations <= 0);
          this.result = 3;
          this.done = true;
        }
        if (!(paramSetResponse.isNXRRSET()))
          break;
        this.result = 4;
        this.answers = null;
        this.done = true;
      }
      if (!(paramSetResponse.isCNAME()))
        break;
      follow(paramSetResponse.getCNAME().getTarget(), paramName);
    }
    if (paramSetResponse.isDNAME())
      localDNAMERecord = paramSetResponse.getDNAME();
    try
    {
      follow(paramName.fromDNAME(localDNAMERecord), paramName);
    }
    catch (NameTooLongException localNameTooLongException)
    {
      do
        while (true)
        {
          this.result = 1;
          this.error = "Invalid DNAME target";
          this.done = true;
        }
      while (!(paramSetResponse.isDelegation()));
      this.referral = true;
    }
  }

  /**
   * @deprecated
   */
  public static void refreshDefault()
  {
    monitorenter;
    try
    {
      try
      {
        defaultResolver = new ExtendedResolver();
        defaultSearchPath = ResolverConfig.getCurrentConfig().searchPath();
        defaultCaches = new HashMap();
        monitorexit;
        return;
      }
      catch (UnknownHostException localUnknownHostException)
      {
        throw new RuntimeException("Failed to initialize resolver");
      }
    }
    finally
    {
      monitorexit;
    }
  }

  private final void reset()
  {
    this.iterations = 0;
    this.foundAlias = false;
    this.done = false;
    this.doneCurrent = false;
    this.aliases = null;
    this.answers = null;
    this.result = -1;
    this.error = null;
    this.nxdomain = false;
    this.badresponse = false;
    this.badresponse_error = null;
    this.networkerror = false;
    this.timedout = false;
    this.nametoolong = false;
    this.referral = false;
    if (this.temporary_cache)
      this.cache.clearCache();
  }

  private void resolve(Name paramName1, Name paramName2)
  {
    Object localObject;
    this.doneCurrent = false;
    if (paramName2 == null)
    {
      localObject = paramName1;
      lookup((Name)localObject);
      return;
    }
    try
    {
      Name localName = Name.concatenate(paramName1, paramName2);
      localObject = localName;
    }
    catch (NameTooLongException localNameTooLongException)
    {
      while (true)
        this.nametoolong = true;
    }
  }

  /**
   * @deprecated
   */
  public static void setDefaultCache(Cache paramCache, int paramInt)
  {
    monitorenter;
    try
    {
      DClass.check(paramInt);
      defaultCaches.put(Mnemonic.toInteger(paramInt), paramCache);
      monitorexit;
      return;
    }
    finally
    {
      localObject = finally;
      monitorexit;
      throw localObject;
    }
  }

  /**
   * @deprecated
   */
  public static void setDefaultResolver(Resolver paramResolver)
  {
    monitorenter;
    try
    {
      defaultResolver = paramResolver;
      monitorexit;
      return;
    }
    finally
    {
      localObject = finally;
      monitorexit;
      throw localObject;
    }
  }

  /**
   * @deprecated
   */
  public static void setDefaultSearchPath(String[] paramArrayOfString)
    throws TextParseException
  {
    monitorenter;
    if (paramArrayOfString == null);
    try
    {
      defaultSearchPath = null;
      monitorexit;
    }
    finally
    {
      while (true)
      {
        Name[] arrayOfName;
        int i;
        monitorexit;
        throw localObject;
        arrayOfName[i] = Name.fromString(paramArrayOfString[i], Name.root);
        ++i;
      }
    }
  }

  /**
   * @deprecated
   */
  public static void setDefaultSearchPath(Name[] paramArrayOfName)
  {
    monitorenter;
    try
    {
      defaultSearchPath = paramArrayOfName;
      monitorexit;
      return;
    }
    finally
    {
      localObject = finally;
      monitorexit;
      throw localObject;
    }
  }

  public Name[] getAliases()
  {
    Name[] arrayOfName;
    checkDone();
    if (this.aliases == null)
      arrayOfName = noAliases;
    while (true)
    {
      return arrayOfName;
      arrayOfName = (Name[])this.aliases.toArray(new Name[this.aliases.size()]);
    }
  }

  public Record[] getAnswers()
  {
    checkDone();
    return this.answers;
  }

  public String getErrorString()
  {
    String str;
    checkDone();
    if (this.error != null)
      str = this.error;
    while (true)
    {
      while (true)
      {
        while (true)
        {
          while (true)
          {
            while (true)
            {
              return str;
              switch (this.result)
              {
              default:
                throw new IllegalStateException("unknown result");
              case 0:
                str = "successful";
              case 1:
              case 2:
              case 3:
              case 4:
              }
            }
            str = "unrecoverable error";
          }
          str = "try again";
        }
        str = "host not found";
      }
      str = "type not found";
    }
  }

  public int getResult()
  {
    checkDone();
    return this.result;
  }

  public Record[] run()
  {
    if (this.done)
      reset();
    if (this.name.isAbsolute())
    {
      resolve(this.name, null);
      if (!(this.done))
      {
        if (!(this.badresponse))
          break label180;
        this.result = 2;
        this.error = this.badresponse_error;
        this.done = true;
      }
    }
    while (true)
    {
      do
        while (true)
        {
          while (true)
          {
            while (true)
            {
              while (true)
              {
                Record[] arrayOfRecord = this.answers;
                while (true)
                {
                  while (true)
                  {
                    return arrayOfRecord;
                    if (this.searchPath != null)
                      break;
                    resolve(this.name, Name.root);
                  }
                  if (this.name.labels() > 1)
                    resolve(this.name, Name.root);
                  if (!(this.done))
                    break;
                  arrayOfRecord = this.answers;
                }
                int i = 0;
                while (true)
                {
                  do
                    while (true)
                    {
                      if (i >= this.searchPath.length);
                      resolve(this.name, this.searchPath[i]);
                      if (!(this.done))
                        break;
                      arrayOfRecord = this.answers;
                    }
                  while (this.foundAlias);
                  ++i;
                }
                label180: if (!(this.timedout))
                  break;
                this.result = 2;
                this.error = "timed out";
                this.done = true;
              }
              if (!(this.networkerror))
                break;
              this.result = 2;
              this.error = "network error";
              this.done = true;
            }
            if (!(this.nxdomain))
              break;
            this.result = 3;
            this.done = true;
          }
          if (!(this.referral))
            break;
          this.result = 1;
          this.error = "referral";
          this.done = true;
        }
      while (!(this.nametoolong));
      this.result = 1;
      this.error = "name too long";
      this.done = true;
    }
  }

  public void setCache(Cache paramCache)
  {
    if (paramCache == null)
    {
      this.cache = new Cache(this.dclass);
      this.temporary_cache = true;
    }
    while (true)
    {
      return;
      this.cache = paramCache;
      this.temporary_cache = false;
    }
  }

  public void setCredibility(int paramInt)
  {
    this.credibility = paramInt;
  }

  public void setResolver(Resolver paramResolver)
  {
    this.resolver = paramResolver;
  }

  public void setSearchPath(String[] paramArrayOfString)
    throws TextParseException
  {
    if (paramArrayOfString == null)
    {
      this.searchPath = null;
      return;
    }
    Name[] arrayOfName = new Name[paramArrayOfString.length];
    int i = 0;
    while (true)
    {
      while (i >= paramArrayOfString.length)
        this.searchPath = arrayOfName;
      arrayOfName[i] = Name.fromString(paramArrayOfString[i], Name.root);
      ++i;
    }
  }

  public void setSearchPath(Name[] paramArrayOfName)
  {
    this.searchPath = paramArrayOfName;
  }
}